﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GeoFits
{
    /// <summary>
    /// 点的数量出错
    /// </summary>
    public class CountOfPointsException : ApplicationException
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public CountOfPointsException() :
            base("Count of Points Error!")
        { }
    }
    /// <summary>
    /// 拟合中一些常用的方法
    /// </summary>
    public class FitHelper
    {
        /// <summary>
        /// 得到点变化量最小的一个方向
        /// </summary>
        /// <param name="pts">输入的点串</param>
        /// <param name="is3d">平面运算还是空间运算</param>
        /// <returns>
        /// X方向变化最小0
        /// Y方向变化最小1
        /// Z方向变化最小2</returns>
        public static int getSmallestDiff(List<Point> pts, bool is3d = false)
        {
            double bigx = double.MinValue;
            double bigy = double.MinValue;
            double bigz = double.MinValue;
            double smallx = double.MaxValue;
            double smally = double.MaxValue;
            double smallz = double.MaxValue;

            if (pts.Count < 2)
                throw new CountOfPointsException(); 

            for (int i = 0; i < pts.Count; i++)
            {
                Point pt = pts[i];
                if (bigx < pt.X)
                    bigx = pt.X;
                if (smallx > pt.X)
                    smallx = pt.X;
                if (bigy < pt.Y)
                    bigy = pt.Y;
                if (smally > pt.Y)
                    smally = pt.Y;


                if (bigz < pt.Z)
                    bigz = pt.Z;
                //ibigz = i;                
                if (smallz > pt.Z)
                    smallz = pt.Z;
                //ismz = i;               
            }
            if(!is3d)
            {
                //只要保证肯定不是Z就可以了
                bigz = double.MaxValue;
                smallz = double.MinValue;
            }
            if ((bigx - smallx) <= (bigy - smally) && (bigx - smallx) <= (bigz - smallz))
                //x变化最小
                return 0;
            if ((bigy - smally) <= (bigx - smallx) && (bigy - smally) <= (bigz - smallz))
                //y变化最小
                return 1;
            else
                //z变化最小
                return 2;
        }
        /// <summary>
        /// 返回距离最远两点决定的向量
        /// 此方法并不完善，只是通过循环两次找到一个相对大的距离的点
        /// </summary>
        /// <param name="pts">点串</param>
        /// <param name="is3d">是否是三维点。当为false时点的Z坐标不参与计算</param>
        /// <returns>向量</returns>
        public static Vector getDiffVector(List<Point> pts, bool is3d = true)
        {
            if(!is3d)
            {
                List<Point> newPts = new List<Point>();
                foreach(var pt in pts)
                {
                    newPts.Add(new Point(pt.X, pt.Y, 0));
                }
                return getDiffVector(newPts, true);
            }
            int n = pts.Count;
            if (n < 2)
                throw new CountOfPointsException();
            else if (n == 2)
                return pts[1] - pts[0];
            
            Point pt1 = pts[0];
            Point pt2 = pts[1];
            double bigDist = pt1.DistanceTo(pt2);
            for(int i = 2; i < n; i++)
            {
                if (pt1.DistanceTo(pts[i]) > bigDist)
                {
                    pt2 = pts[i];
                    bigDist = pt1.DistanceTo(pts[i]);
                }
            }
            for (int i = 0; i < n; i++)
            {
                if (pt2.DistanceTo(pts[i]) > bigDist)
                {
                    pt1 = pts[i];
                    bigDist = pt2.DistanceTo(pts[i]);
                }
            }
            return pt2 - pt1;
        }
    }
}
